﻿using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.DirectoryServices.Protocols;
using ActiveDirectoryUtilities.CommonLibrary.Unsafe;

namespace ActiveDirectoryUtilities.DirectoryServiceAccess
{
	public class DomainTrust : IComparable<DomainTrust>
	{
		private string _netbiosDomainName = string.Empty, _dnsDomainName = string.Empty;
		private NetApi32.DS_DOMAIN _flags;
		private NetApi32.TRUST_TYPE _trustType;
		private NetApi32.TRUST_ATTRIBUTE _trustAttributes;
		private Domain _sourceDomain;
		private DateTime _pwdLastSet = GlobalMethods.ConvertInt64ToDateTime(null);
		private SecurityIdentifier _domainSid;
		private Guid _domainGuid;
		private Exception _targetDomainAccessErrors = null;

		internal DomainTrust(NetApi32.DS_DOMAIN_TRUSTS trust, Domain sourceDomain)
		{
			_netbiosDomainName = trust.NetbiosDomainName;
			_dnsDomainName = trust.DnsDomainName;
			_flags = trust.Flags;
			_trustType = trust.TrustType;
			_trustAttributes = trust.TrustAttributes;
			if ((this._trustType & NetApi32.TRUST_TYPE.MIT) == 0)
			{
				_domainSid = new SecurityIdentifier(trust.DomainSid);
			}

			_domainGuid = trust.DomainGuid;

			_sourceDomain = sourceDomain;
			if ((this._flags & NetApi32.DS_DOMAIN.DIRECT_INBOUND) == NetApi32.DS_DOMAIN.DIRECT_INBOUND)
			{
				WLdapSearchRequest wlsr = new WLdapSearchRequest(
					sourceDomain.DnsDomainName
					, (int)LDAP_PORTS.LDAP
					, sourceDomain.NcName
					, "(sAMAccountName=" + this.TargetNetbiosDomainName + "$)"
					, System.DirectoryServices.Protocols.SearchScope.Subtree);

				wlsr.Attributes.Add("pwdLastSet");
				SearchResultEntry trustObject = wlsr.FindOne();
				if ((trustObject != null) && (trustObject.Attributes.Contains("pwdLastSet")))
				{
					_pwdLastSet = GlobalMethods.ConvertInt64ToDateTime(trustObject.Attributes["pwdLastSet"]);
				}
			}
		}

		public string TargetNetbiosDomainName { get { return this._netbiosDomainName; } }

		public string TargetDnsDomainName { get { return this._dnsDomainName; } }

		public string TargetDomainName { get { return !string.IsNullOrEmpty(this._dnsDomainName) ? this._dnsDomainName : this._netbiosDomainName; } }

		public Exception TargetDomainAccessIssues { get { return _targetDomainAccessErrors; } }

		public Domain SourceDomain { get { return _sourceDomain; } }

		public DateTime PasswordLastSet { get { return _pwdLastSet; } }

		public SecurityIdentifier TargetDomainSid { get { return this._domainSid; } }

		public NetApi32.DS_DOMAIN Flags { get { return this._flags; } }

		public NetApi32.TRUST_ATTRIBUTE TrustAttributes { get { return this._trustAttributes; } }

		public NetApi32.TRUST_TYPE TrustType { get { return this._trustType; } }

		public Guid TargetDomainGuid { get { return this._domainGuid; } }

		public bool SelectiveAuthEnabled { get { return (this._trustAttributes & NetApi32.TRUST_ATTRIBUTE.CROSS_ORGANIZATION) == NetApi32.TRUST_ATTRIBUTE.CROSS_ORGANIZATION; } }

		public bool SidFilteringEnabled { get { return (this._trustAttributes & NetApi32.TRUST_ATTRIBUTE.QUARANTINED_DOMAIN) == NetApi32.TRUST_ATTRIBUTE.QUARANTINED_DOMAIN; } }

		//public string VerifyOutboundTrust()
		//{
		//    if ((this._flags & DS_DOMAIN.DIRECT_OUTBOUND) != 0)
		//    {
		//        try
		//        {
		//            this._sourceDomain.VerifyOutboundTrustRelationship(this.TargetDomainName);
		//            return "Active";
		//        }
		//        //Handle the domain being unresolvable
		//        catch (ActiveDirectoryObjectNotFoundException e)
		//        {
		//            return e.Message.Trim();
		//        }
		//        //Handle access denied - if it can return an error, the domain is alive.
		//        catch (UnauthorizedAccessException e)
		//        {
		//            return e.Message.Trim();
		//        }
		//        catch (Exception e)
		//        {
		//            return e.GetType().ToString() + " - " + e.Message.Trim();
		//        }
		//    }
		//}

		//    return string.Empty;
		//}

		//public string VerifyInboundTrust()
		//{
		//    if ((this._flags & DS_DOMAIN.DIRECT_INBOUND) != 0)
		//    {
		//        try
		//        {
		//            Domain target = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, this.TargetDomainName));
		//            target.VerifyOutboundTrustRelationship(this.SourceDomain);
		//            //d.VerifyTrustRelationship(Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, this.TargetDomainName)), tri.TrustDirection);
		//            return "Active";
		//        }
		//        catch (ActiveDirectoryObjectNotFoundException e)
		//        {
		//            return e.Message.Trim();
		//        }
		//        //Handle access denied - if it can return an error, the domain is alive.
		//        catch (UnauthorizedAccessException e)
		//        {
		//            return e.Message.Trim();
		//        }
		//        catch (Exception e)
		//        {
		//            return e.GetType().ToString() + " - " + e.Message.Trim();
		//        }
		//    }

		//    return string.Empty;
		//}

		#region IComparable<DS_DOMAIN_TRUSTS> Members
		public int CompareTo(DomainTrust other)
		{
			if ((!string.IsNullOrEmpty(this.TargetDnsDomainName)) && (!string.IsNullOrEmpty(other.TargetDnsDomainName)))
			{
				return this.TargetDnsDomainName.CompareTo(other.TargetDnsDomainName);
			}
			else
			{
				return this.TargetNetbiosDomainName.CompareTo(other.TargetNetbiosDomainName);
			}
		}
		#endregion
	}
}
